#include<iostream>
using namespace std;

//class A
//{
//public:
//	int _a;
//};
//
//// class B : public A
//class B : virtual public A
//{
//public:
//	int _b;
//};
//
//// class C : public A
//class C : virtual public A
//{
//public:
//	int _c;
//};
//
//class D : public B, public C
//{
//public:
//	int _d;
//};
//
//int main()
//{
//	D d;
//	d.B::_a = 1;
//	d.C::_a = 2;
//	d._a = 3;
//	d._b = 4;
//	d._c = 5;
//	d._d = 6;
//
//	B b;
//	b._a = 7;
//	b._b = 8;
//
//	// B的指针指向B对象
//	B* p2 = &b;
//	// B的指针指向D对象切片
//	B* p1 = &d;
//
//	// p1和p2分别对指向的_a成员访问修改
//	// 分析内存模型，我们发现B对象也使用了虚基表指向A成员的模型
//	// 所以打开汇编我们看到下面的访问_a的方式是一样的
//	p1->_a++;
//	p2->_a++;
//
//	return 0;
//}

//class Base {
//public:
//	virtual void func1() { cout << "Base::func1" << endl; }
//	virtual void func2() { cout << "Base::func2" << endl; }
//private:
//	int a;
//};
//
//class Derive :public Base {
//public:
//	virtual void func1() { cout << "Derive::func1" << endl; }
//	virtual void func3() { cout << "Derive::func3" << endl; }
//	virtual void func4() { cout << "Derive::func4" << endl; }
//	virtual void func5() { cout << "Derive::func5" << endl; }
//private:
//	int b;
//};
//
//typedef void(*VFPTR) ();
////void PrintVTable(VFPTR vTable[])
//void PrintVTable(VFPTR* vTable)
//{
//	// 依次取虚表中的虚函数指针打印并调用。调用就可以看出存的是哪个函数
//	cout << " 虚表地址>" << vTable << endl;
//	// 注意如果是在g++下面，这里就不能用nullptr去判断访问虚表结束了
//	for (int i = 0; vTable[i] != nullptr; ++i)
//	{
//		printf(" 第%d个虚函数地址 :0X%p,->", i, vTable[i]);
//		VFPTR f = vTable[i];
//		f();
//	}
//	cout << endl;
//}
//
//int main()
//{
//	Base b;
//	Derive d;
//	// 32位程序的访问思路如下：
//	// 需要注意的是如果是在64位下，指针是8byte，对应程序位置就需要进行更改
//	// 思路：取出b、d对象的头4bytes，就是虚表的指针，前面我们说了虚函数表本质是一个存虚
//	// 函数指针的指针数组，vs下这个数组最后面放了一个nullptr，g++下面最后没有nullptr
//	// 1.先取b的地址，强转成一个int*的指针
//	// 2.再解引用取值，就取到了b对象头4bytes的值，这个值就是指向虚表的指针
//	// 3.再强转成VFPTR*，因为虚表就是一个存VFPTR类型(虚函数指针类型)的数组。
//	// 4.虚表指针传递给PrintVTable进行打印虚表
//	// 5.需要说明的是这个打印虚表的代码经常会崩溃，因为编译器有时对虚表的处理不干净，虚
//	// 表最后面没有放nullptr，导致越界，这是编译器的问题。我们只需要点目录栏的 - 生成 - 清理解决方
//	// 案，再编译就好了。
//	VFPTR * vTable1 = (VFPTR*)(*(int*)&b);
//	PrintVTable(vTable1);
//
//	VFPTR* vTable2 = (VFPTR*)(*(int*)&d);
//	PrintVTable(vTable2);
//
//	return 0;
//}

//class Base1 {
//public:
//	virtual void func1() { cout << "Base1::func1" << endl; }
//	virtual void func2() { cout << "Base1::func2" << endl; }
//private:
//	int b1;
//};
//
//class Base2 {
//public:
//	virtual void func1() { cout << "Base2::func1" << endl; }
//	virtual void func2() { cout << "Base2::func2" << endl; }
//private:
//	int b2;
//};
//
//class Derive : public Base1, public Base2 {
//public:
//	virtual void func1() { cout << "Derive::func1" << endl; }
//	virtual void func3() { cout << "Derive::func3" << endl; }
//private:
//	int d1;
//};
//
//typedef void(*VFPTR) ();
//void PrintVTable(VFPTR vTable[])
//{
//	cout << " 虚表地址>" << vTable << endl;
//	for (int i = 0; vTable[i] != nullptr; ++i)
//	{
//		printf(" 第%d个虚函数地址 :0X%p,->", i, vTable[i]);
//		VFPTR f = vTable[i];
//		f();
//	}
//	cout << endl;
//}
//
//int main()
//{
//	Derive d;
//	VFPTR* vTableb1 = (VFPTR*)(*(int*)&d);
//	PrintVTable(vTableb1);
//
//	//VFPTR* vTableb2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1)));
//	Base2* ptr = &d;
//	VFPTR* vTableb2 = (VFPTR*)(*(int*)(ptr));
//	PrintVTable(vTableb2);
//
//	Base1* p1 = &d;
//	p1->func1();
//
//	Base2* p2 = &d;
//	p2->func1();
//
//	d.func1();
//
//	return 0;
//}

class A
{
public:
	virtual void func1() {}
public:
	int _a;
};

class B : virtual public A
{
public:
	virtual void func1() {}
	virtual void func2() {}
public:
	int _b;
};

class C : virtual public A
{
public:
	virtual void func1() {}
	virtual void func3() {}
public:
	int _c;
};

class D : public B, public C
{
public:
	D()
		:_d(1)
	{
	}
	inline virtual void func1() {}
	virtual void func4() {}
public:
	int _d;
};

int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._a = 3;
	d._b = 4;
	d._c = 5;
	d._d = 6;

	return 0;
}
